﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Xml;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Management.Automation;

namespace Readify.Management.Automation.GoGrid
{
    public static class GoGridHelper
    {
        private static DateTime m_EpochDate = new DateTime(1970, 1, 1);

        public static int CalculateSecondsSinceEpochDate()
        {
            TimeSpan elapsedTimeSinceEpochDate = DateTime.UtcNow - GoGridHelper.m_EpochDate;
            int elapsedTimeInSecondsSinceEpochDate = (int)elapsedTimeSinceEpochDate.TotalSeconds;
            return elapsedTimeInSecondsSinceEpochDate;
        }

        public static string GenerateRequestSignature(string apiKey, string secret)
        {
            int elapsedTimeInSecondsSinceEpochDate = GoGridHelper.CalculateSecondsSinceEpochDate();
            string input = string.Format("{0}{1}{2}", apiKey, secret, elapsedTimeInSecondsSinceEpochDate);

            byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
            byte[] outputBytes = provider.ComputeHash(inputBytes);

            StringBuilder builder = new StringBuilder();
            foreach (byte outputByte in outputBytes)
            {
                builder.AppendFormat("{0:x2}", outputByte);
            }

            string output = builder.ToString();
            return output;
        }

        public static XmlDocument ProcessRequest(string url, Cmdlet cmdlet)
        {
            HttpWebResponse response = null;
            XmlDocument responseDocument = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                response = (HttpWebResponse)request.GetResponse();

                using (Stream responseStream = response.GetResponseStream())
                {
                    responseDocument = new XmlDocument();
                    responseDocument.Load(responseStream);
                }
            }
            catch (WebException ex)
            {
                HttpWebResponse errorResponse = (HttpWebResponse)ex.Response;
                string errorMessage = string.Format(
                    "Cmdlet received an error from the GoGrid API. The URL generated was '{0}'. The HTTP status code " +
                    "was '{1} ({2})'. Please refer to GoGrid API reference at " +
                    "http://wiki.gogrid.com/wiki/index.php/API for more details or download " +
                    "an updated set of Cmdlets from CodePlex at " +
                    "http://www.codeplex.com/gogridpssnapin/. The underlying error is " +
                    "enclosed as an inner exception.",
                    url,
                    errorResponse.StatusCode,
                    (int)errorResponse.StatusCode
                    );
                GoGridException wrapperEx = new GoGridException(errorMessage, ex);
                wrapperEx.Url = url;

                if (ex.Response.ContentLength != 0)
                {
                    using (Stream errorStream = ex.Response.GetResponseStream())
                    {
                        XmlDocument errorDocument = new XmlDocument();
                        errorDocument.Load(errorStream);
                        wrapperEx.ErrorDocument = errorDocument;

                        XmlNodeList objectElementNodeList = errorDocument.SelectNodes("/gogrid/response/list/object[@name = 'error']");

                        List<GoGridError> listOfErrors = new List<GoGridError>();
                        foreach (XmlNode objectElementNode in objectElementNodeList)
                        {
                            GoGridError error = GoGridError.CreateFromXmlNode(objectElementNode);
                            listOfErrors.Add(error);
                        }
                        wrapperEx.Errors = listOfErrors.ToArray();
                    }
                }
                
                string errorId = errorResponse.StatusCode.ToString();
                ErrorRecord record = new ErrorRecord(wrapperEx, errorId, ErrorCategory.NotSpecified, null);
                cmdlet.ThrowTerminatingError(record);
            }

            return responseDocument;
        }

        public static XmlNode GetAttributeElementFromXmlNodeAsXmlNode(XmlNode objectElementNode, string name)
        {
            string xpathExpression = string.Format("attribute[@name = '{0}']", name);
            XmlNode attributeElementNode = objectElementNode.SelectSingleNode(xpathExpression);
            return attributeElementNode;
        }

        public static string GetAttributeElementValueFromXmlNodeAsString(XmlNode objectElementNode, string name)
        {
            XmlNode attributeElementNode = GoGridHelper.GetAttributeElementFromXmlNodeAsXmlNode(objectElementNode, name);
            string value = attributeElementNode.InnerText;
            return value;
        }

        public static XmlNode GetAttributeElementFromXmlNodeAsFirstChildXmlNode(XmlNode objectElementNode, string name)
        {
            XmlNode attributeElementNode = GoGridHelper.GetAttributeElementFromXmlNodeAsXmlNode(objectElementNode, name);
            XmlNode attributeElementFirstChildNode = attributeElementNode.ChildNodes[0];
            return attributeElementFirstChildNode;
        }

        public static int? GetAttributeElementValueFromXmlNodeAsNullableInt32(XmlNode objectElementNode, string name)
        {
            string valueAsString = GoGridHelper.GetAttributeElementValueFromXmlNodeAsString(objectElementNode, name);

            if (string.IsNullOrEmpty(valueAsString))
            {
                return null;
            }

            int value = int.Parse(valueAsString);
            return value;
        }

        public static int GetAttributeElementValueFromXmlNodeAsInt32(XmlNode objectElementNode, string name)
        {
            int? value = GoGridHelper.GetAttributeElementValueFromXmlNodeAsNullableInt32(objectElementNode, name);
            return value ?? -1;
        }

        public static bool GetAttributeElementValueFromXmlNodeAsBoolean(XmlNode objectElementNode, string name)
        {
            string valueAsString = GoGridHelper.GetAttributeElementValueFromXmlNodeAsString(objectElementNode, name);
            bool value = bool.Parse(valueAsString);
            return value;
        }

        public static bool? GetAttributeElementValueFromXmlNodeAsNullableBoolean(XmlNode objectElementNode, string name)
        {
            string valueAsString = GoGridHelper.GetAttributeElementValueFromXmlNodeAsString(objectElementNode, name);

            if (string.IsNullOrEmpty(valueAsString))
            {
                return null;
            }
            
            bool value = bool.Parse(valueAsString);
            return value;
        }

        public static DateTime? GetAttributeElementValueFromXmlNodeAsNullableDateTime(XmlNode objectElementNode, string name)
        {
            string valueAsString = GoGridHelper.GetAttributeElementValueFromXmlNodeAsString(objectElementNode, name);

            if (string.IsNullOrEmpty(valueAsString))
            {
                return null;
            }
            
            DateTime value = DateTime.Parse(valueAsString);
            return value;
        }
    }
}
